#include "SNLBPCalculator.h"
#include <stdint.h>
//----------------------------------------------------------------

SNLBPCalculator::SNLBPCalculator()
{
}
//----------------------------------------------------------------

SNLBPCalculator::~SNLBPCalculator()
{
}

void SNLBPCalculator::Calculate(const cv::Mat& in_data, cv::Mat& out_data)
{
	uint8_t* src_ptr = in_data.data + in_data.cols + 1;
	
	out_data = cv::Mat(in_data.rows, in_data.cols, CV_8UC1);
	
	uint8_t* dst_ptr = out_data.data + out_data.cols + 1;

	for (int32_t r = 1; r < in_data.rows - 1; ++r)
	{
		for (int32_t c = 1; c < in_data.cols - 1; ++c)
		{
			uint8_t lbp = 0;

			uint8_t cp = src_ptr[0];
			
			if (src_ptr[1] > cp)
				lbp |= 1;
			lbp <<= 1;

			if (src_ptr[in_data.cols + 1] > cp)
				lbp |= 1;
			lbp <<= 1;

			if (src_ptr[in_data.cols] > cp)
				lbp |= 1;
			lbp <<= 1;

			if (src_ptr[in_data.cols - 1] > cp)
				lbp |= 1;
			lbp <<= 1;

			if (src_ptr[-1] > cp)
				lbp |= 1;
			lbp <<= 1;

			if (src_ptr[-in_data.cols - 1] > cp)
				lbp |= 1;
			lbp <<= 1;

			if (src_ptr[-in_data.cols] > cp)
				lbp |= 1;
			lbp <<= 1;

			if (src_ptr[-in_data.cols + 1] > cp)
				lbp |= 1;
			//lbp <<= 1;

			*dst_ptr = lbp;
			src_ptr++;
			dst_ptr++;
		}

		src_ptr += 2;
		dst_ptr += 2;
	}
}
//----------------------------------------------------------------

void SNLBPCalculator::Init(const cv::Mat& image)
{
	Offsets = cv::Mat(image.cols * image.rows * 8, 1, CV_8UC4);
	CenterOffsets = cv::Mat(image.cols * image.rows, 1, CV_8UC4);

	uint32_t count = 0;

	for (int y = 0; y < image.rows; ++y)
	{
		for (int x = 0; x < image.cols; ++x)
		{
			for (int k = 0; k < 8; ++k)
			{
				int dx = 0; 
				int dy = 0;

				switch (k)
				{
				case 0: dx = 1; dy = 0; break;
				case 1: dx = 1; dy = 1; break;
				case 2: dx = 0; dy = 1; break;
				case 3: dx = -1; dy = 1; break;
				case 4: dx = -1; dy = 0; break;
				case 5: dx = -1; dy = -1; break;
				case 6: dx = 0; dy = -1; break;
				case 7: dx = 1; dy = -1; break;
				}

				if (x + dx < 0 || x + dx >= image.cols)
					dx = 0;

				if (y + dy < 0 || y + dy >= image.rows)
					dy = 0;

				uint32_t offset = (y + dy) * image.step + (x + dx);

				Offsets.at<uint32_t>(count++) = offset;
			}

			CenterOffsets.at<uint32_t>(y * image.cols + x) = y * image.step + x;
		}
	}
}

void SNLBPCalculator::Calculate2(const cv::Mat& in_data, cv::Mat& out_data)
{
	uint8_t* src_ptr = (uint8_t*)in_data.data;
	uint8_t* dst_ptr = (uint8_t*)out_data.data;

	uint32_t* center_offsets = (uint32_t*)CenterOffsets.data;
	uint32_t* offsets = (uint32_t*)Offsets.data;

	int32_t count = 0;

	for (int i = 0; i < in_data.cols * in_data.rows; ++i)
	{
		uint8_t cp = src_ptr[center_offsets[i]];

		uint8_t lbp = 0;
		for (int k = 0; k < 8; ++k)
		{
			lbp <<= 1;

			if (src_ptr[offsets[count++]] > cp)
			{
				lbp |= 1;
			}
		}

		dst_ptr[i] = lbp;
	}
}
//----------------------------------------------------------------